/*
 * 
 */

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "rp2040.h"
#include "hardware/structs/uart.h"
#include "hardware/clocks.h"
#include "hardware/resets.h"
#include "hardware/gpio.h"
#include "hardware/i2c.h"

/**/
#include "pico.h"
#include "pico/multicore.h"

#include "dbg_cli.h"

#include "ttusb_comn.h"
#include "ttusb.h"

#include "msgpool.h"
#include "umsg.h"


void tttdelay( uint32_t cnt )
{
	uint32_t  i;

	for (i=0; i<cnt; i++ ) {
		__NOP();
	}
}


/* 8N1, 115200 */
void ttt_uart0_init( void )
{
	uart0_hw->ibrd = 26;
	uart0_hw->fbrd = 3;
	uart0_hw->lcr_h = UART_UARTLCR_H_WLEN_BITS | UART_UARTLCR_H_FEN_BITS;
	uart0_hw->cr = UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS;
	uart0_hw->dmacr = UART_UARTDMACR_TXDMAE_BITS | UART_UARTDMACR_RXDMAE_BITS;
}



static uint32_t ttt_ticks = 0;

void  SysTick_Handler( void )
{
	ttt_ticks += 1;

#if 0
	if ( ttt_ticks & 0x2 )  {
		gpio_put( 25, true );
	} else {
		gpio_put( 25, false );
	}
#endif

	return;
}


void HardFault_exception( void )
{
	printf( "hard fault ...\n" );
	while ( 1 )  {
		__asm volatile ( "nop" );
		__asm volatile ( "wfi" );
	}
}


int  ttt_cmd_cpsr( void * pctx, int argc, const char *argv[] )
{
	int  iret;
	uint32_t  temp;

	if ( argc < 2 )  {
		printf( "ticks = %u\n", ttt_ticks );
		goto usage;
	}

	/**/
	iret = debug_str2uint( argv[1], &temp );
	if ( iret != 0 )  {
		printf( "arg1, fmt err, %d\n", iret );
		goto usage;
	}

	switch (temp ) {
	case 0:
		temp = __get_CONTROL();
		printf( "control : %X\n", temp );
		break;
		
	case 1:
		temp = __get_xPSR();
		printf( "xpsr : %X\n", temp );
		break;

	case 2:
		temp = __get_PRIMASK();
		printf( "primask : %X\n", temp );
		break;

	default:
		break;
	}

	/**/
	return 0;

usage:
	printf("%s <0-3>\n", argv[0]);
	return 0;
}


int  ttt_cmd_clock( void * pctx, int argc, const char *argv[] )
{
	int iret;
	uint32_t temp;
	uint32_t hzhz;

	if ( argc < 2 ) {
		goto usage;
	}

	/**/
	iret = debug_str2uint( argv[1], &temp );
	if ( iret != 0 )  {
		printf( "arg1, fmt err, %d\n", iret );
		goto usage;
	}

	/**/
	hzhz = clock_get_hz( (int)temp );
	printf( "clk %u : %u hz\n", temp, hzhz );
	return 0;

usage:
	printf("%s <0-9>\n", argv[0]);
	return 0;	
}


int  ttt_cmd_umsg( void * pctx, int argc, const char *argv[] )
{
	void * ptr;


	if ( argc < 2 ) {

		ptr = umsg_recv();
		printf( "recv %p\n", ptr );
		if ( ptr != NULL ) {
			debug_dump_hex( ptr, 80 );
		}

	} else {

		int i;
		umsg_t * pmsg;

		pmsg = (umsg_t * )msg_alloc();
		if ( pmsg == NULL ) {
			printf( "msg, alloc, fail\n" );
			return 0;
		}

		for ( i=0; i<64; i++ ) {
			pmsg->data[i] = (uint8_t)(0x10 + i);
		}

		pmsg->mlen = 21;
		pmsg->type = 0xAA;
		umsg_send( pmsg );
	}

	return 0;
}



extern void con_proc_input( void );
extern void core_zero_proc_msg( void );
extern void core1_main( void );
extern int utchan_init();

int main( void )
{
	int iret;
	uint32_t  temp;

	/* uart0,  clock enable */
	hw_set_bits( &clocks_hw->wake_en1, CLOCKS_WAKE_EN1_CLK_SYS_UART0_BITS | CLOCKS_WAKE_EN1_CLK_PERI_UART0_BITS );
	hw_set_bits( &clocks_hw->wake_en0, CLOCKS_WAKE_EN0_CLK_SYS_I2C0_BITS );

	/* un reset */
	unreset_block_wait( RESETS_RESET_PADS_BANK0_BITS );
	unreset_block_wait( RESETS_RESET_IO_BANK0_BITS );
	unreset_block_wait( RESETS_RESET_UART0_BITS );
	
	/* gpio-0:uart0-tx,  gpio-1:uart0-rx */
	gpio_pull_up( 12 );
	gpio_pull_up( 13 );
	gpio_set_function( 12, GPIO_FUNC_UART );
	gpio_set_function( 13, GPIO_FUNC_UART );

	/**/
	ttt_uart0_init();

	/* I2C */
	gpio_pull_up( 0 );
	gpio_pull_up( 1 );
	gpio_set_input_enabled( 0, true );
	gpio_set_input_enabled( 1, true );
	gpio_set_input_hysteresis_enabled( 0, true );
	gpio_set_input_hysteresis_enabled( 1, true );
	gpio_set_slew_rate( 0, GPIO_SLEW_RATE_SLOW );
	gpio_set_slew_rate( 1, GPIO_SLEW_RATE_SLOW );
	gpio_set_function( 0, GPIO_FUNC_I2C );
	gpio_set_function( 1, GPIO_FUNC_I2C );

	/**/
	debug_cli_init();
	debug_add_cmd( "cpsr", ttt_cmd_cpsr, 		NULL );
	debug_add_cmd( "clock", ttt_cmd_clock, 		NULL );

	/**/
	iret = msg_pool_init(64);
	printf( "msg pool, ret = %d\n", iret );
	umsg_init();

	/* core-1 */
	multicore_launch_core1_raw( core1_main, (uint32_t *)(uintptr_t)0x20042000, 0x10000100 );
	NVIC_EnableIRQ( SIO_IRQ_PROC0_IRQn );

	/* usb auto */
	ttusb_desc_init();
	ttusb_desc_device_vid_pid( 0x2E8A, 0x1013 );
	ttusb_desc_device_str_manu( "TTusb" );
	ttusb_desc_device_str_prod( "Dapk" );
	ttusb_desc_config_power( 0x64 );
	ttusb_desc_interface_add_inp( umsg_inp_cbk );
	ttusb_desc_interface_add_outp( umsg_outp_cbk );
	ttusb_init();

	/**/
	utchan_init();
	
	/**/
	SysTick_Config( 9000000 );
	printf("hello...\n");

	/**/
	while ( 1 )  {

		con_proc_input();

		/**/
		core_zero_proc_msg();

		/**/
		__WFI();
	}

	return 0;
}

